/**version:1.0.0
 * 传入歌词，按照正则表达式解析
 * 解析的数据结构为：
 * {
 *   txt:歌词，
 *   time:ms
 * }
 */
/* 要歌词长这样↓
[by:坚瓠]
[00:02.120]只是对你有些厌倦
[00:04.370]因你感到有点孤单
[00:06.770]我的激情慢慢点燃
[00:09.020]别再占据我的脑海
[00:09.620]因为我无法停止想念
[00:12.320]感觉有些抱歉
[00:14.530]但我仍想与你再续前缘
[00:16.790]我不想浪费时间
[00:18.890]也不想与你说再见
[00:21.440]这感觉已经融入我脑海
[00:23.040]
[00:23.880]融入我身心
[00:26.030]可我无法拒绝
[00:29.290]不 我无法拒绝
[00:31.990]你在我脑海里徘徊
[00:33.480]玩弄我的真心
[00:34.190]抚摸我的身体
[00:36.330]但我无法就这样放弃
[00:39.370]不 我无法放弃
[00:42.520]妈的我恨你
[00:46.270]呵我依然爱你
[00:48.670]你撕碎我的心
[00:51.720]彻彻底底
[00:53.920]所以我陷入纠结
[00:56.360]我继续玩着你的游戏
[00:59.220]但我已经无法克制自己
[01:01.420]我依然爱你
[01:07.870]我依然爱你
[01:13.280]（依然爱你）
[01:14.790]几近疯癫
[01:17.150]坐在原地等你
[01:19.510]只是有点难过而已
[01:21.400]我就要离开这里
[01:22.460]我不想独自留在家里
[01:24.920]感觉如此抱歉
[01:27.460]但我想与你相伴
[01:30.010]正值午夜
[01:31.660]我不想与你告别
[01:34.670]这感觉已经融入我脑海
[01:35.820]
[01:36.680]融入我身心
[01:38.720]可我无法拒绝
[01:42.220]不 我无法拒绝
[01:44.820]你在我脑海里徘徊
[01:45.980]玩弄我的真心
[01:47.240]抚摸我的身体
[01:49.650]但我无法就这样放弃
[01:52.740]不 我无法放弃
[01:56.050]妈的我恨你
[01:58.700]呵我依然爱你
[02:01.520]你撕碎我的心
[02:04.120]彻彻底底
[02:06.720]所以我陷入纠结
[02:09.310]我继续玩着你的游戏
[02:11.970]但我已经无法克制自己
[02:15.320]我依然爱你
[02:20.670]我依然爱你
[02:25.120]我依然爱你
[02:31.010]我依然爱你
[02:36.960]（我依然爱你）
[02:38.170]妈的我恨你
[02:40.460]呵我依然爱你
[02:43.200]你撕碎我的心
[02:45.810]彻彻底底
[02:48.260]所以我陷入纠结
[02:51.010]我继续玩着你的游戏
[02:53.510]但我已经无法克制自己
[02:56.010]我依然爱你
[02:59.410]妈的我恨你
[03:01.310]呵我依然爱你
[03:03.770]你撕碎我的心
[03:06.420]彻彻底底
[03:09.060]所以我陷入纠结
[03:11.570]我继续玩着你的游戏
[03:14.570]但我已经无法克制自己
[03:17.110]我依然爱你
[03:22.960]我依然爱你
[03:27.170]我依然爱你"
*/

// eslint-disable-next-line
const timeExp = /\[(\d{2,}):(\d{2})(?:[\.\:](\d{2,3}))?]/g

const STATE_PAUSE = 0
const STATE_PLAYING = 1

const tagRegMap = {
  title: 'ti',
  artist: 'ar',
  album: 'al',
  offset: 'offset',
  by: 'by'
}

function noop() {
}

export default class Lyric {
  constructor(lrc, hanlder = noop, speed = 1) {
    this.lrc = lrc
    this.tags = {}
    this.lines = []
    this.handler = hanlder
    this.state = STATE_PAUSE
    this.curLineIndex = 0
    this.speed = speed
    this.offset = 0

    this._init()
  }

  _init() {
    this._initTag()

    this._initLines()
  }

  //lrc里并不一定都是歌词 还有作者撒的(title、artist、album、offset、by
  //比如 [by:坚瓠]
  _initTag() {
    for (let tag in tagRegMap) {
      const matches = this.lrc.match(new RegExp(`\\[${tagRegMap[tag]}:([^\\]]*)]`, 'i'))
      this.tags[tag] = matches && (matches[1] || '')
    }
  }

  _initLines() {
    const lines = this.lrc.split('\n')
    for (let i = 0; i < lines.length; i++) {
      const line = lines[i] //[01:44.820]你在我脑海里徘徊
      let result = timeExp.exec(line) //const timeExp = /\[(\d{2,}):(\d{2})(?:[\.\:](\d{2,3}))?]/g
      if (result) {
        const txt = line.replace(timeExp, '').trim(); //你在我脑海里徘徊

        if (txt) {
          /*
            [
              '[00:02.120]',
              '00',
              '02',
              '120',
              index: 0,
              input: '[00:02.120]只是对你有些厌倦',
              groups: undefined
            ]
          */
          if (result[3].length === 3) {
            result[3] = result[3]/10;
          }
          this.lines.push({
            time: result[1] * 60 * 1000/*分钟换算成毫秒*/ + result[2] * 1000/*秒换算成毫秒*/ + (result[3] || 0) * 10,
            txt
          })
        }
      }
    }

    //给每句歌词排序 时间搓小的在前面
    this.lines.sort((a, b) => {
      return a.time - b.time
    })

  }

  //拖拽进度条时 会走 Player/index.js 里的 onProgressChange
  //里面会调 currentLyric.current.seek(newTime * 1000) （newTime 是根据percent计算而来
  seek(offset) {
    this.play(offset, true)
  }

  //offset为时间进度
  //isSeek表示是否是用户手动调整
  play(offset = 0, isSeek = false) {
    if (!this.lines.length) {
      return
    }
    this.state = STATE_PLAYING

    this.curLineIndex = this._findCurLineIndex(offset)
    //现在正处于第this.curLineIndex-1行
    //因为 _findCurLineIndex 返回的是 比offset 大的那一行
    // , 即即将跳转的那一行歌词
    // , 但并不是当前应该展示的那一行
    // 故这里减一 (但这里有个极端情况 就是第一句歌词
    this._callHandler(this.curLineIndex-1)
    this.offset = offset
    this.startStamp = +new Date() - offset

    if (this.curLineIndex < this.lines.length) {
      clearTimeout(this.timer)
      this._playRest(isSeek)
    }
  }

  _findCurLineIndex(time) {
    for (let i = 0; i < this.lines.length; i++) {
      if (time <= this.lines[i].time) {
        return i
      }
    }
    return this.lines.length - 1
  }

  _callHandler(i) {
    if (i < 0) {
      return
    }
    this.handler({
      txt: this.lines[i].txt,
      lineNum: i
    })
  }

  _playRest(isSeek=false) {
    let line = this.lines[this.curLineIndex] //即将展示的下一行
    let delay;
    if(isSeek) {
      delay = line.time - (+new Date() - this.startStamp)/*当前行歌词已经展现的时间*/;
    }else {
      //拿到上一行的歌词开始时间，算间隔
      let preTime = this.lines[this.curLineIndex - 1] ? this.lines[this.curLineIndex - 1].time : 0;
      delay = line.time - preTime;
    }
    this.timer = setTimeout(() => {
      this._callHandler(this.curLineIndex++/*←传入的是当前行 但传入后curLineIndex已经+1,也就是说下次再执行_playRest,curLineIndex已经是最新的*/)
      if (this.curLineIndex < this.lines.length && this.state === STATE_PLAYING) {
        this._playRest()
      }
    }, (delay / this.speed))
  }

  togglePlay(offset) {
    if (this.state === STATE_PLAYING) {
      this.stop()
      this.offset = offset
    } else {
      this.state = STATE_PLAYING
      this.play(offset, true)
    }
  }

  stop() {
    this.state = STATE_PAUSE
    this.offset = 0
    clearTimeout(this.timer)
  }

  changeSpeed(speed) {
    this.speed = speed;
  }
}
